package com.es.demo.service.impl;

import com.es.demo.constant.enums.IndexEnum;
import com.es.demo.service.BasicEsService;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.RangeQueryBuilder;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.SortBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.*;
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.data.elasticsearch.core.query.Query;
import org.springframework.stereotype.Service;

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
public class BasicEsServiceImpl<T> implements BasicEsService<T> {

    @Autowired
    protected ElasticsearchRestTemplate elasticsearchRestTemplate;

    @Override
    public void save(IndexEnum indexEnum, T... ts) {
        T[] save = elasticsearchRestTemplate.save(ts, IndexCoordinates.of(indexEnum.getIndex()));
        return;
    }

    @Override
    public void delete(IndexEnum indexEnum, String id) {
        String delete = elasticsearchRestTemplate.delete(id, IndexCoordinates.of(indexEnum.getIndex()));
    }

    @Override
    public T getById(IndexEnum indexEnum, String id, T clazz) {
        elasticsearchRestTemplate.get(id, clazz.getClass(), IndexCoordinates.of(indexEnum.getIndex()));
        return null;
    }

    @Override
    public List<T> getAllData(IndexEnum indexEnum, T clazz) {
        Query query = new NativeSearchQueryBuilder()
                .withQuery(QueryBuilders.matchAllQuery()).build();
        SearchHits<T> searchHits = (SearchHits<T>) elasticsearchRestTemplate.search(query, clazz.getClass(), IndexCoordinates.of(indexEnum.getIndex()));
        return searchHits.get().map(SearchHit::getContent).collect(Collectors.toList());
    }

    @Override
    public List<Map<String, Object>> query(String sql, T clazz) {

        throw new AbstractMethodError();
    }

    @Override
    public Page<T> rangeQuery(Integer pageNo, Integer pageSize, IndexEnum indexEnum, Map<String, String> order, Map<String, Object[]> rangeParam, T clazz) {
        //范围查询
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        rangeParam.keySet().forEach(field -> {
            boolQueryBuilder.must(new RangeQueryBuilder(field).gt(rangeParam.get(field)[0]).lt(rangeParam.get(field)[1]));
        });
        PageRequest of = PageRequest.of(pageNo, pageSize);
        List<FieldSortBuilder> sortBuilderList = order.keySet().stream()
                .map(field -> SortBuilders.fieldSort(field).order(SortOrder.valueOf(order.get(field))))
                .collect(Collectors.toList());
        Query searchQuery = new NativeSearchQueryBuilder()
                .withQuery(boolQueryBuilder)
                .withPageable(of)
                .withSorts((SortBuilder<?>) sortBuilderList)
                .build();
        SearchHits<T> searchHits = (SearchHits<T>) elasticsearchRestTemplate.search(searchQuery, clazz.getClass());
        SearchPage<T> searchHits1 = SearchHitSupport.searchPageFor(searchHits, searchQuery.getPageable());
        return new PageImpl<>(searchHits.get().map(SearchHit::getContent).collect(Collectors.toList()), searchHits1.getPageable(), searchHits1.getTotalElements());
    }

    @Override
    public Page<T> pageList(Integer pageNo, Integer pageSize, String keyword, T clazz, Map<String, String> order, String... fields) {
        //分页，页码从0开始
        PageRequest of = PageRequest.of(pageNo, pageSize);
        List<FieldSortBuilder> collect = order.keySet().stream()
                .map(field -> SortBuilders.fieldSort(field).order(SortOrder.valueOf(order.get(field))))
                .collect(Collectors.toList());

        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        Arrays.asList(fields).forEach(e -> boolQueryBuilder.should(QueryBuilders.fuzzyQuery(e, keyword)));
        Query searchQuery = new NativeSearchQueryBuilder()
                //条件
                .withQuery(boolQueryBuilder)
                //分页
                .withPageable(of)
                //排序
                .withSorts((SortBuilder<?>) collect)
                .build();
        SearchHits<T> searchHits = (SearchHits<T>) elasticsearchRestTemplate.search(searchQuery, clazz.getClass());
        SearchPage<T> searchHits1 = SearchHitSupport.searchPageFor(searchHits, searchQuery.getPageable());
        return new PageImpl<>(searchHits.get().map(SearchHit::getContent).collect(Collectors.toList()), searchHits1.getPageable(), searchHits1.getTotalElements());
    }
}
